package com.heiyu.api.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Range;
import com.google.gson.JsonObject;
import com.heiyu.api.controller.dto.PicInfo;
import com.heiyu.api.request.CoinPriceGetRequest;
import com.heiyu.api.request.CoinPriceMarketRequest;
import com.heiyu.api.request.CoinRangeRequest;
import com.heiyu.api.response.CoinPriceGetResponse;
import com.heiyu.api.response.CoinPriceMarketResponse;
import com.heiyu.api.response.model.*;
import com.heiyu.controller.ApiBaseController;
import com.heiyu.dao.*;
import com.heiyu.entity.*;
import com.heiyu.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by mountain on 18/6/11.
 */
@Api(description = "币种行情")
@RestController
@RequestMapping("api/v1/coin/price")
public class CoinPriceController extends ApiBaseController{

    @Autowired
    private GlobalShowInfoMapper globalShowInfoMapper;
    @Autowired
    private ShowFlow1dMapper showFlow1dMapper;
    @Autowired
    private ShowInfoMapper showInfoMapper;
    @Autowired
    private MarketBaseInfoMapper marketBaseInfoMapper;
    @Autowired
    private ShowFull30minMapper showFull30minMapper;
    @Autowired
    private UserFollowMapper userFollowMapper;
    @Autowired
    private MarketCoinCoinMapper marketCoinCoinMapper;
    @ApiOperation(value="get",notes = "获取币种详情")
    @RequestMapping(value = "get",method = RequestMethod.GET)
    public CoinPriceGetResponse get(@ModelAttribute CoinPriceGetRequest request){
        UserInfo userInfo = getUser();
        CoinPriceGetResponse response = new CoinPriceGetResponse();
        response.success();
        CoinPriceGetModel model = new CoinPriceGetModel();
        GlobalShowInfo globalShowInfo = new GlobalShowInfo();
        globalShowInfo.setTargetId(request.getTargetId());
        globalShowInfo = globalShowInfoMapper.selectList(globalShowInfo).get(0);
        CoinBaseInfo baseInfo = coinBaseInfoUtils.get(request.getTargetId());
        if(baseInfo == null){
            baseInfo = new CoinBaseInfo();
        }
        model.setName(baseInfo.getSymbol());
        model.setFullName(baseInfo.getUsName());
        model.setLogoUrl(baseInfo.getLogo());
        model.setCnName(baseInfo.getCnName());
        model.setDiffPirce(RangeUtil.diffPrice(defaultSymbol()?globalShowInfo.getPriceCny():globalShowInfo.getPriceUsd(),globalShowInfo.getPercentChange24h()));
        model.setCirculationSupply(""+baseInfo.getCirculationSupply());
        model.setTargetId(baseInfo.getTargetId());
        if(defaultSymbol()){
            model.setPrice(MoneyUtils.formatter(globalShowInfo.getPriceCny(),false));
            model.setValueAmount(MoneyUtils.formatter(globalShowInfo.getMarketCapCny(),true));
            model.setTradeAmount(MoneyUtils.formatter(globalShowInfo.getVol24hCny(),true));
        }else{
            model.setPrice(MoneyUtils.formatter(globalShowInfo.getPriceUsd(),false));
            model.setTradeAmount(MoneyUtils.formatter(globalShowInfo.getVol24hUsd(),true));
            model.setValueAmount(MoneyUtils.formatter(globalShowInfo.getMarketCapUsd(),true));
        }
        model.setExchangePirce(MoneyUtils.formatter(globalShowInfo.getPriceUsd(),false));
        model.setGlobalValuePrecent(RangeUtil.formatter(globalShowInfo.getMarketCapCny().multiply(new BigDecimal("100")).divide(globalShowInfoMapper.targetMarketPrecent(request.getTargetId()),2,2)));
        model.setIcoPrice(baseInfo.getIssuePrice());
        model.setRange(RangeUtil.formatter(globalShowInfo.getPercentChange24h()));
        model.setNetAddress(baseInfo.getWebsite());
        model.setPublishTime(DateUtils.format(baseInfo.getCreateTime(),"yyyy/MM/dd"));
        model.setPublishNum(baseInfo.getMaxSupply());
        model.setContent(baseInfo.getDescCn());
        model.setTurnOver(RangeUtil.formatterNoFlag(globalShowInfo.getTurnover()));
        if(userInfo != null){
            try{
                UserFollow follow = new UserFollow();
                follow.setFCoin(baseInfo.getTargetId());
                follow.setUserName(userInfo.getTelphone());
                follow  = this.userFollowMapper.selectList(follow).get(0);
                model.setCollectId(follow.getId());
            }catch (Exception e){

            }
        }
        String str = redisUtils.get("RATE_USD_CNY");
        BigDecimal rate = new BigDecimal(str);
        List<BigDecimal> flow = Lists.newArrayList();
        flow.add(globalShowInfo.getNetflow1d());
        List<ShowFlow1d> flowInfoList = this.showFlow1dMapper.list6day(request.getTargetId());
        model.setWeekFlowList(Lists.newArrayList());
        FlowInfo flowInfo  = new FlowInfo();
        flowInfo.setDate(DateUtils.format(new Date(),"MM/dd"));
        if(defaultSymbol()){
            flowInfo.setFundInAmount(MoneyUtils.formatter(MoneyUtils.changeSymbolType(globalShowInfo.getInflow1d(),rate),true));
            flowInfo.setFundOutAmount(MoneyUtils.formatter(MoneyUtils.changeSymbolType(globalShowInfo.getOutflow1d(),rate),true));
            if(globalShowInfo.getInflow1d()!=null)
                flowInfo.setFundInAmountData(MoneyUtils.changeSymbolType(globalShowInfo.getInflow1d(),rate).longValue());
            if(globalShowInfo.getOutflow1d() != null)
                flowInfo.setFundOutAmountData(MoneyUtils.changeSymbolType(globalShowInfo.getOutflow1d(),rate).longValue());
            flowInfo.setMaxPrice(MoneyUtils.formatter(MoneyUtils.changeSymbolType(globalShowInfo.getHigh1d(),rate),false));
            flowInfo.setMinPrice(MoneyUtils.formatter(MoneyUtils.changeSymbolType(globalShowInfo.getLow1d(),rate),false));
            flowInfo.setNetFlowAmount(MoneyUtils.formatter(MoneyUtils.changeSymbolType(globalShowInfo.getNetflow1d(),rate),true));
        }else{
            flowInfo.setFundInAmount(MoneyUtils.formatter(globalShowInfo.getInflow1d(),true));
            flowInfo.setFundOutAmount(MoneyUtils.formatter(globalShowInfo.getOutflow1d(),true));
            if(globalShowInfo.getInflow1d()!=null)
                flowInfo.setFundInAmountData(globalShowInfo.getInflow1d().longValue());
            if(globalShowInfo.getOutflow1d() != null)
                flowInfo.setFundOutAmountData(globalShowInfo.getOutflow1d().longValue());
            flowInfo.setMaxPrice(MoneyUtils.formatter(globalShowInfo.getHigh1d(),false));
            flowInfo.setMinPrice(MoneyUtils.formatter(globalShowInfo.getLow1d(),false));
            flowInfo.setNetFlowAmount(MoneyUtils.formatter(globalShowInfo.getNetflow1d(),true));
        }
        flowInfo.setTradeRate(RangeUtil.formatterNoFlag(globalShowInfo.getTurnover()));
        if(globalShowInfo.getNetflow1d()!=null)
        flowInfo.setNetFlowFlag(globalShowInfo.getNetflow1d().intValue()>0?"I":"O");
        model.setDayFlow(flowInfo);
        if(flowInfoList!=null){
            List<BigDecimal> highList = new ArrayList<BigDecimal>();
            List<BigDecimal> lowList = new ArrayList<BigDecimal>();
            for(ShowFlow1d info:flowInfoList){
                highList.add(defaultSymbol()?MoneyUtils.changeSymbolType(info.getHigh1d(),rate):info.getHigh1d());
                lowList.add(defaultSymbol()?MoneyUtils.changeSymbolType(info.getLow1d(),rate):info.getLow1d());
            }
            highList.add(defaultSymbol()?MoneyUtils.changeSymbolType(globalShowInfo.getHigh1d(),rate):globalShowInfo.getHigh1d());
            lowList.add(defaultSymbol()?MoneyUtils.changeSymbolType(globalShowInfo.getHigh1d(),rate):globalShowInfo.getLow1d());
            BigDecimal highPrice = KlineUtils.max(highList);
            BigDecimal lowPrice =KlineUtils.min(lowList);

            for(ShowFlow1d info:flowInfoList){
                if(DateUtils.format(info.getCreateTime(),"yyyyMMdd").equals(DateUtils.format(new Date(),"yyyyMMdd"))){
                    continue;
                }
                flowInfo = new FlowInfo();
                flowInfo.setDate(DateUtils.format(info.getCreateTime(),"MM/dd"));
                if(defaultSymbol()){
                    flowInfo.setFundInAmount(MoneyUtils.formatter(MoneyUtils.changeSymbolType(info.getInflow1d(),rate),true));
                    flowInfo.setFundOutAmount(MoneyUtils.formatter(MoneyUtils.changeSymbolType(info.getOutflow1d(),rate),true));
                    flowInfo.setFundInAmountData(MoneyUtils.changeSymbolType(info.getInflow1d(),rate).longValue());
                    flowInfo.setFundOutAmountData(MoneyUtils.changeSymbolType(info.getOutflow1d(),rate).longValue());
                    flowInfo.setNetFlowAmount(MoneyUtils.formatter(MoneyUtils.changeSymbolType(globalShowInfo.getNetflow1d(),rate),true));
                }else{
                    flowInfo.setFundInAmount(MoneyUtils.formatter(info.getInflow1d(),true));
                    flowInfo.setFundOutAmount(MoneyUtils.formatter(info.getOutflow1d(),true));
                    flowInfo.setFundInAmountData(info.getInflow1d().longValue());
                    flowInfo.setFundOutAmountData(info.getOutflow1d().longValue());
                    flowInfo.setNetFlowAmount(MoneyUtils.formatter(globalShowInfo.getNetflow1d(),true));
                }

                flowInfo.setMaxPrice(MoneyUtils.formatterCoin(highPrice));
                flowInfo.setMinPrice(MoneyUtils.formatterCoin(lowPrice));
                flowInfo.setTradeRate(RangeUtil.formatterNoFlag(globalShowInfo.getTurnover()));
                if(globalShowInfo.getNetflow1d()!= null){
                    flowInfo.setNetFlowFlag(globalShowInfo.getNetflow1d().intValue()>0?"I":"O");
                }else{
                    flowInfo.setNetFlowFlag("I");
                }
                flow.add(defaultSymbol()?MoneyUtils.changeSymbolType(globalShowInfo.getNetflow1d(),new BigDecimal(str)):globalShowInfo.getNetflow1d());
                model.getWeekFlowList().add(flowInfo);
            }
            model.getWeekFlowList().add(model.getDayFlow());
            BigDecimal weekFlow = KlineUtils.count(flow);
            if(weekFlow.doubleValue()>=0){
                model.setWeekNetFlowFlag("I");
            }else{
                model.setWeekNetFlowFlag("O");
            }
            model.setWeekNetFlowAmount(MoneyUtils.formatter(weekFlow,true));
        }

        //获取有该币交易的交易所
        Map<String,Object> param = PageUtils.newParam(request.getPageIndex(),request.getPageSize());
        param.put("usName",model.getFullName());
        param.put("marketCoin","USD/USDT");
        List<ShowInfo> marketList  = showInfoMapper.selectMarketList(param);
        model.setMarketTradeList(Lists.newArrayList());
        List<MarketBaseInfo> marketBaseInfoList = this.marketBaseInfoMapper.selectList(new MarketBaseInfo());
        if(marketList!=null){
            MarketTradeInfo marketTradeInfo;
            for(ShowInfo info:marketList){
                marketTradeInfo = new MarketTradeInfo();
                marketTradeInfo.setName(info.getMarketName());
                if(defaultSymbol()){
                    marketTradeInfo.setPrice(MoneyUtils.formatter(info.getPriceCny(),false));
                    marketTradeInfo.setTradeAmount(MoneyUtils.formatter(info.getVol24hCny(),true));
                }else{
                    marketTradeInfo.setPrice(MoneyUtils.formatter(info.getPriceUsd(),false));
                    marketTradeInfo.setTradeAmount(MoneyUtils.formatter(info.getVol24hUsd(),true));
                }
                marketTradeInfo.setExchangePirce(MoneyUtils.formatter(info.getPriceUsd(),false));
                marketTradeInfo.setRange(RangeUtil.formatter(info.getPercentChange24h()));
                for(MarketBaseInfo marketBaseInfo:marketBaseInfoList){
                    if(marketBaseInfo.getMarketName().equals(info.getMarketName())){
                        marketTradeInfo.setLogoUrl(marketBaseInfo.getLogo());
                        break;
                    }
                }
                marketTradeInfo.setHasPic(hasPic(info.getSymbol(),info.getTCoin(),info.getMarketName()));
                model.getMarketTradeList().add(marketTradeInfo);
            }
        }
        //获取币对币行情
        param.remove("marketCoin");
        marketList = showInfoMapper.selectMarketList(param);
        model.setCoinPairList(Lists.newArrayList());
        CoinPairInfo pairInfo;
        MarketBaseInfo marketBaseInfo = new MarketBaseInfo();
        List<MarketBaseInfo> targetMarketBaseList;
        for(ShowInfo showInfo:marketList){
            pairInfo = new CoinPairInfo();
            pairInfo.setRange(RangeUtil.formatter(showInfo.getPercentChange24h()));
            pairInfo.setMarketName(showInfo.getMarketName());
            pairInfo.setKlinePicId("1");
            marketBaseInfo.setMarketName(showInfo.getMarketName());
            targetMarketBaseList = this.marketBaseInfoMapper.selectList(marketBaseInfo);
            if(!CollectionUtils.isEmpty(targetMarketBaseList)){
                pairInfo.setHasPic(hasPic(showInfo.getSymbol(),showInfo.getTCoin(),targetMarketBaseList.get(0).getBlockccName()));
            }else{
                pairInfo.setHasPic("N");
            }
            //pairInfo.setHasPic(hasPic(showInfo.getSymbol(),showInfo.getTCoin(),showInfo.getMarketName()));
            pairInfo.setCoinName(showInfo.getSymbol());
            pairInfo.setExchangeCoinName(showInfo.getTCoin());
            if(defaultSymbol()){
                pairInfo.setPrice(MoneyUtils.formatter(showInfo.getPriceCny(),false));
            }else{
                pairInfo.setPrice(MoneyUtils.formatter(showInfo.getPriceUsd(),false));
            }

            pairInfo.setExchangePirce(MoneyUtils.formatterCoin(showInfo.getPriceNative()));
            pairInfo.setTradeAmount(MoneyUtils.formatter(showInfo.getVol24hCny(),true));
            model.getCoinPairList().add(pairInfo);
        }
        //根据日期类型获取点数据
        model.setKlineList(getKline(model.getTargetId(),request.getDayType()));
        //交易所成交量占比
        model.setBasePicPontList(Lists.newArrayList());
        String objStr = redisUtils.get("G_M_PERCENT_"+globalShowInfo.getSymbol());
        if(objStr != null){
            PicInfo info =  JSON.parseObject(objStr,PicInfo.class);
            PicPointInfo picPointInfo;
            for(int i=0;i<info.getKey().size();i++){
                picPointInfo = new PicPointInfo();
                picPointInfo.setName(info.getKey().get(i));
                picPointInfo.setPrecentDesc(RangeUtil.formatterNoFlag(info.getValue().get(i)));
                picPointInfo.setPrecent(info.getValue().get(i).multiply(new BigDecimal("100")).intValue());
                model.getBasePicPontList().add(picPointInfo);
            }
        }
        //交易对占比
        model.setPairPicPontList(Lists.newArrayList());
        objStr = redisUtils.get("G_CC_PERCENT_"+globalShowInfo.getSymbol());
        if(objStr != null){
            PicInfo info =  JSON.parseObject(objStr,PicInfo.class);
            PicPointInfo picPointInfo;
            for(int i=0;i<info.getKey().size();i++){
                picPointInfo = new PicPointInfo();
                picPointInfo.setName(info.getKey().get(i));
                picPointInfo.setPrecentDesc(RangeUtil.formatterNoFlag(info.getValue().get(i)));
                picPointInfo.setPrecent(info.getValue().get(i).multiply(new BigDecimal("100")).intValue());
                model.getPairPicPontList().add(picPointInfo);
            }
        }
        response.setData(model);
        return response;
    }



    @ApiOperation(value="market/list",notes = "获取币种详情市场列表")
    @RequestMapping(value = "market/list",method = RequestMethod.GET)
    public CoinPriceMarketResponse marketList(@ModelAttribute CoinPriceMarketRequest request){
        CoinPriceMarketResponse response = new CoinPriceMarketResponse();
        response.success();
        CoinPriceMarket model = new CoinPriceMarket();
        CoinBaseInfo baseInfo = coinBaseInfoUtils.get(request.getTargetId());
        Map<String,Object> param = PageUtils.newParam(request.getPageIndex(),request.getPageSize());
        param.put("usName",baseInfo.getUsName());
        param.put("marketCoin","USD/USDT");
        if(!StringUtils.isEmpty(request.getPriceType())){
            param.put("priceDesc",request.getPriceType().equals("U")?"desc":"asc");
        }
        if(!StringUtils.isEmpty(request.getRangeType())){
            param.put("rangeDesc",request.getRangeType().equals("U")?"desc":"asc");
        }
        List<ShowInfo> marketList  = showInfoMapper.selectMarketList(param);
        model.setList(Lists.newArrayList());
        List<MarketBaseInfo> marketBaseInfoList = this.marketBaseInfoMapper.selectList(new MarketBaseInfo());
        if(marketList!=null){
            MarketTradeInfo marketTradeInfo;
            for(ShowInfo info:marketList){
                marketTradeInfo = new MarketTradeInfo();
                marketTradeInfo.setName(info.getMarketName());
                marketTradeInfo.setTargetId(info.getId()+"");
                if(defaultSymbol()){
                    marketTradeInfo.setPrice(MoneyUtils.formatter(info.getPriceCny(),false));
                    marketTradeInfo.setTradeAmount(MoneyUtils.formatter(info.getVol24hCny(),true));
                }else{
                    marketTradeInfo.setPrice(MoneyUtils.formatter(info.getPriceUsd(),false));
                    marketTradeInfo.setTradeAmount(MoneyUtils.formatter(info.getVol24hUsd(),true));
                }
                marketTradeInfo.setExchangePirce(MoneyUtils.formatter(info.getPriceUsd(),false));
                marketTradeInfo.setRange(RangeUtil.formatter(info.getPercentChange24h()));
                marketTradeInfo.setHasPic(hasPic(info.getSymbol(),info.getTCoin(),info.getMarketName()));
                for(MarketBaseInfo marketBaseInfo:marketBaseInfoList){
                    if(marketBaseInfo.getMarketName().equals(info.getMarketName())){
                        marketTradeInfo.setLogoUrl(marketBaseInfo.getLogo());
                        break;
                    }
                }
                model.getList().add(marketTradeInfo);
            }
        }
        response.setData(model);
        return response;
    }

    private String hasPic(String usName,String toCoin,String marketName){
        if(marketName.indexOf(".")>=0){
            marketName = marketName.replace(".","");
        }
        MarketCoinCoin cMarketCoinCoin = new MarketCoinCoin();
        cMarketCoinCoin.setFCoin(usName);
        cMarketCoinCoin.setTCoin(toCoin);
        cMarketCoinCoin.setMarketName(marketName);
        List<MarketCoinCoin> list = this.marketCoinCoinMapper.selectList(cMarketCoinCoin);
        if(CollectionUtils.isEmpty(list))
            return "N";
        if(list.get(0).getHasKline()!=null && list.get(0).getHasKline()==1){
            return "Y";
        }
        return "N";
    }

    private List<PointInfo> getKline(String usName,String type){
        List<PointInfo> pointInfoList = Lists.newArrayList();
        Map<String,Object> param = Maps.newHashMap();
        param.put("targetId",usName);
        List<ShowFull30min> list = null;
        PointInfo pointInfo;
        if(StringUtils.isEmpty(type)){
            type = "1";
        }
        switch (type){
            case "1":
                param.put("offset",48);
                list =  this.showFull30minMapper.selectForKline(param);
                if(list != null && list.size()>0){
                    for(ShowFull30min info:list){
                        pointInfo = new PointInfo();
                        pointInfo.setDateTime(DateUtils.format(info.getCreateTime(),"yyyy/MM/dd HH:mm"));
                        pointInfo.setPrice(MoneyUtils.formatter(defaultSymbol()?info.getPriceCny():info.getPriceUsd(),false));
                        pointInfo.setTimestamp(Integer.valueOf(info.getCreateTime().getTime()/1000+""));
                        pointInfoList.add(pointInfo);
                    }
                }
                break;
            case "2":
                param.put("offset",296);
                list =  this.showFull30minMapper.selectForKline(param);
                if(list != null && list.size()>0){
                    for(int i=0;i<list.size();i++){
                        if(i%8==0||list.size()-1==i){
                            pointInfo = new PointInfo();
                            pointInfo.setDateTime(DateUtils.format(list.get(i).getCreateTime(),"yyyy/MM/dd HH:mm"));
                            pointInfo.setPrice(MoneyUtils.formatter(defaultSymbol()?list.get(i).getPriceCny():list.get(i).getPriceUsd(),false));
                            pointInfo.setTimestamp(Integer.valueOf(list.get(i).getCreateTime().getTime()/1000+""));
                            pointInfoList.add(pointInfo);
                        }
                    }
                }
                break;
            case "3":
                param.put("offset",1176);
                list =  this.showFull30minMapper.selectForKline(param);
                if(list != null && list.size()>0){
                    for(int i=0;i<list.size();i++){
                        if(i%24==0||list.size()-1==i){
                            pointInfo = new PointInfo();
                            pointInfo.setDateTime(DateUtils.format(list.get(i).getCreateTime(),"yyyy/MM/dd HH:mm"));
                            pointInfo.setPrice(MoneyUtils.formatter(defaultSymbol()?list.get(i).getPriceCny():list.get(i).getPriceUsd(),false));
                            pointInfo.setTimestamp(Integer.valueOf(list.get(i).getCreateTime().getTime()/1000+""));
                            pointInfoList.add(pointInfo);
                        }
                    }
                }
                break;
            case "4":
                param.put("offset",14112);
                list =  this.showFull30minMapper.selectForKline(param);
                if(list != null && list.size()>0){
                    for(int i=0;i<list.size();i++){
                        if(i%296==0||list.size()-1==i){
                            pointInfo = new PointInfo();
                            pointInfo.setDateTime(DateUtils.format(list.get(i).getCreateTime(),"yyyy/MM/dd HH:mm"));
                            pointInfo.setPrice(MoneyUtils.formatter(defaultSymbol()?list.get(i).getPriceCny():list.get(i).getPriceUsd(),false));
                            pointInfo.setTimestamp(Integer.valueOf(list.get(i).getCreateTime().getTime()/1000+""));
                            pointInfoList.add(pointInfo);
                        }
                    }
                }
                break;
        }
        return Lists.reverse(pointInfoList);
    }
}
